package ypmits.sound {
	import ypmits.sound.totest.PitchShift;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.media.ID3Info;
	import flash.media.Sound;
	import flash.media.SoundLoaderContext;
	import flash.net.URLRequest;
	import flash.utils.getDefinitionByName;

	/**
	 * The SoundManager tracks and updates a collection of sounds. 
	 * This is particullary usefull when the volume of a collection of sounds
	 * has to be updated. The SoundManager dispatches 'Event.CHANGE' events
	 * when the volume is updated.
	 * 
	 * @author Hugo Dechesne
	 */
	public class SoundManager extends EventDispatcher implements ISoundManager {

		private static var _instance : SoundManager;
		private var _volume : Number;
		private var _pitchshift : PitchShift;
		private var sound : Sound;

		
		/**
		 * Creates a new instance of SoundManager
		 * 
		 * @param volume The volume of all sounds controller by this SoundManager
		 */
		function SoundManager( volume : Number = 1 ) {
			_volume = volume;
		}

		
		public static function get instance() : SoundManager {
			if( _instance == null) {
				_instance = new SoundManager( );
			}
			
			return _instance;
		}

		[Bindable(event=Event.CHANGE)]

		
		/**
		 * 
		 * @param value The volume
		 * 
		 */
		public function set volume(value : Number) : void {
			trace( "SoundManager.volume("+[value]+")" );
			_volume = value;
			
			// update all sound controls
			dispatchEvent( new Event( Event.CHANGE, false, false ) );
		}

		
		/**
		 * 
		 * @return The volume
		 * 
		 */
		public function get volume() : Number {
			return _volume;
		}

		
		/**
		 * Add an existing SoundAsset to this SoundManager.
		 * The SoundManager creates a SoundControl which can be used
		 * to control the SoundAsset.
		 * 
		 * @param sound The existing SoundAsset
		 * @return The created SoundControl
		 * 
		 */
		public function addSound(sound : Sound) : ISoundControl {
			return new SoundControl( sound, this );
		}

		
		/**
		 * Creates a new SoundAsset from the specified Class and creates 
		 * a SoundControl which can be used to control the SoundAsset.
		 * 
		 * @param soundCls The Class which creates the SoundAsset
		 * @return The created SoundControl
		 * 
		 */
		public function createSound(soundCls : Class) : ISoundControl {
			var snd : Sound;
			try {
				snd = new soundCls as Sound;
			} catch(e : Error) { 
				trace( e ); 
			}
			
			return new SoundControl( snd, this );
		}

		
		/**
		 * Creates a SoundControl from a class definition. If the definition is not found
		 * the SoundControl will contain an empty Sound object, so no sound will be played
		 * 
		 * @param definition The defition of the sound class 
		 */
		public function createSoundFromDefinition(definition : String) : ISoundControl {	
			try {		
				var cls : Class = getDefinitionByName( definition ) as Class;			
				return createSound( cls );
			} catch(e : Error) { 
			}
			
			return addSound( null );
		}

		
		/**
		 * Creates a new streaming SoundAsset from the specified url, and creates 
		 * a SoundControl which can be used to control the SoundAsset.
		 * 
		 * @param url The url of the sound file
		 * @param context The SoundLoaderContext that is used
		 * @return The created SoundControl
		 * 
		 */
		public function createStream(url : String, context : SoundLoaderContext = null) : ISoundControl {
			if( ! context ) {
				context = new SoundLoaderContext( 1000, false );
			}
			sound = new Sound( );
			_pitchshift = new PitchShift( sound );
			
			sound.addEventListener( IOErrorEvent.IO_ERROR, soundErrorHandler );
			sound.addEventListener( Event.ID3, soundID3Handler );
			var urlRequest : URLRequest = new URLRequest( url );
			
			// load stream
			sound.load( urlRequest, context );
			
			// return control
			return new SoundControl( sound, this );
		}

		
		private function soundID3Handler(event : Event) : void {
			var id3 : ID3Info = ID3Info( event.target['id3'] );
			trace( "Received ID3 Info:" );
			for (var pName:String in id3) {
				trace( pName + " = " + id3[pName] );
			}
		}

		
		private function soundErrorHandler(event : IOErrorEvent) : void {
			trace( "SoundManager.soundErrorHandler(" + [ event ] + ")" );
		}

		
		/**
		 * Closes all sounds
		 */
		public function unload() : void {
			dispatchEvent( new Event( Event.UNLOAD ) );
		}
		
		
		public function get pitchshift() : PitchShift {
			return _pitchshift;
		}
		
		
		public function set pitchshift( p : PitchShift ) : void {
			_pitchshift = p;
		}

		
		public function play( ) : void {
			_pitchshift.play();
		}
	}
}